package dao

import (
	"context"
	"sale-admin/internal/dal"
	"sale-admin/internal/models"
	"strings"
	"time"

	"192.168.1.75/go-pkg/helper"
	"github.com/golang-module/carbon/v2"
	"gorm.io/gen/field"
	"gorm.io/gorm"
)

type GoodsDailyReportInterface interface {
	WithGoodsID(goodsID string) GoodsDailyReportInterface
	WithGoodsName(goodsName string) GoodsDailyReportInterface
	WithMerchantID(merchantID string) GoodsDailyReportInterface
	WithLocationID(locationID string) GoodsDailyReportInterface
	WithRobotID(robotID string) GoodsDailyReportInterface
	WithProvinceID(provinceID string) GoodsDailyReportInterface
	WithCityID(cityID string) GoodsDailyReportInterface
	WithTimePeriod(start int64, end int64) GoodsDailyReportInterface
	WithPaginate(page, size int) GoodsDailyReportInterface
	WithGroupType(int) GoodsDailyReportInterface
	WithOrderType(string) GoodsDailyReportInterface
	WithSummary(int) GoodsDailyReportInterface

	List() ([]*models.GoodsDailyReport, int64, *models.GoodsDailyReport, error)

	WithGMV(value float64) GoodsDailyReportOption
	WithPaymentAmount(value float64) GoodsDailyReportOption
	WithTransactionAmount(value float64) GoodsDailyReportOption
	WithDiscountAmount(value float64) GoodsDailyReportOption
	WithRefundAmount(value float64) GoodsDailyReportOption
	WithGiveAmount(value float64) GoodsDailyReportOption
	WithTotalOrder(value int64) GoodsDailyReportOption
	WithTotalPaidOrder(value int64) GoodsDailyReportOption
	WithTotalNotPaidOrder(value int64) GoodsDailyReportOption
	WithTotalRefundOrder(value int64) GoodsDailyReportOption
	WithTotalPaidUser(value int64) GoodsDailyReportOption
	WithTotalGoodsClick(value int64) GoodsDailyReportOption
}

type GoodsDailyReport struct {
	Ctx       context.Context
	Query     *dal.Query
	Tx        dal.IGoodsDailyReportDo
	StartTime int64
	EndTime   int64
	Summary   int
	GroupType int
	Page      int
	Limit     int
}

func NewGoodsDailyReport(ctx context.Context, db *gorm.DB) GoodsDailyReportInterface {
	return &GoodsDailyReport{
		Ctx:   ctx,
		Query: dal.Use(db),
		Tx:    dal.Use(db).GoodsDailyReport.WithContext(ctx),
	}
}

// 查询字段
func (r GoodsDailyReport) getSelectField() []field.Expr {
	m := r.Query.GoodsDailyReport
	return []field.Expr{
		m.GoodsID, m.GoodsName,
		m.GMV.Sum().As(m.GMV.ColumnName().String()),
		m.PaymentAmount.Sum().As(m.PaymentAmount.ColumnName().String()),
		m.TransactionAmount.Sum().As(m.TransactionAmount.ColumnName().String()),
		m.RefundAmount.Sum().As(m.RefundAmount.ColumnName().String()),
		m.GiveAmount.Sum().As(m.GiveAmount.ColumnName().String()),
		m.DiscountAmount.Sum().As(m.DiscountAmount.ColumnName().String()),
		m.TotalOrder.Sum().As(m.TotalOrder.ColumnName().String()),
		m.TotalPaidOrder.Sum().As(m.TotalPaidOrder.ColumnName().String()),
		m.TotalNotPaidOrder.Sum().As(m.TotalNotPaidOrder.ColumnName().String()),
		m.TotalRefundOrder.Sum().As(m.TotalRefundOrder.ColumnName().String()),
		m.TotalPaidUser.Sum().As(m.TotalPaidUser.ColumnName().String()),
		m.TotalGoodsClick.Sum().As(m.TotalGoodsClick.ColumnName().String()),
	}
}

// 条件 商户
func (r GoodsDailyReport) WithMerchantID(merchantID string) GoodsDailyReportInterface {
	m := r.Query.GoodsDailyReport
	if merchantID != "" {
		r.Tx = r.Tx.Where(m.MerchantID.In(strings.Split(merchantID, ",")...))
	} else {
		r.Tx = r.Tx.Where(field.NewInt(m.TableName(), m.MerchantID.ColumnName().String()).Gt(1))
	}
	return r
}

// 条件 商场
func (r GoodsDailyReport) WithLocationID(locationID string) GoodsDailyReportInterface {
	m := r.Query.GoodsDailyReport
	if locationID != "" {
		r.Tx = r.Tx.Where(m.LocationID.In(strings.Split(locationID, ",")...))
	}
	return r
}

// 条件 机器
func (r GoodsDailyReport) WithRobotID(robotID string) GoodsDailyReportInterface {
	m := r.Query.GoodsDailyReport
	if robotID != "" {
		r.Tx = r.Tx.Where(m.RobotName.In(strings.Split(robotID, ",")...))
	}
	return r
}

// 条件 商品ID
func (r GoodsDailyReport) WithGoodsID(goodsID string) GoodsDailyReportInterface {
	m := r.Query.GoodsDailyReport
	if goodsID != "" {
		r.Tx = r.Tx.Where(m.GoodsID.In(strings.Split(goodsID, ",")...))
	}
	return r
}

// 条件 商品名称
func (r GoodsDailyReport) WithGoodsName(goodsName string) GoodsDailyReportInterface {
	m := r.Query.GoodsDailyReport
	if goodsName != "" {
		// 时间段内的所有去重的商品名称
		var goodsNames []string
		m.WithContext(r.Ctx).Where(m.CreatedDate.Between(time.Unix(r.StartTime, 0), time.Unix(r.EndTime, 0))).
			Group(m.GoodsName).
			Pluck(m.GoodsName, &goodsNames)
		var validGoodsNames []string
		for _, v := range goodsNames {
			if strings.Contains(v, goodsName) {
				validGoodsNames = append(validGoodsNames, v)
			}
		}
		r.Tx = r.Tx.Where(m.GoodsName.In(validGoodsNames...))
	}
	return r
}

// 条件 省份id
func (r GoodsDailyReport) WithProvinceID(provinceID string) GoodsDailyReportInterface {
	m := r.Query.GoodsDailyReport
	if provinceID != "" {
		r.Tx = r.Tx.Where(m.ProvinceID.In(strings.Split(provinceID, ",")...))
	}
	return r
}

// 条件 城市id
func (r GoodsDailyReport) WithCityID(cityID string) GoodsDailyReportInterface {
	m := r.Query.GoodsDailyReport
	if cityID != "" {
		r.Tx = r.Tx.Where(m.CityID.In(strings.Split(cityID, ",")...))
	}
	return r
}

// 条件 起止时间
func (r GoodsDailyReport) WithTimePeriod(startTime, endTime int64) GoodsDailyReportInterface {
	m := r.Query.GoodsDailyReport
	if startTime != 0 && endTime != 0 {
		r.Tx = r.Tx.Where(m.CreatedDate.Between(
			time.Unix(startTime, 0),
			time.Unix(endTime, 0),
		))
		r.StartTime = startTime
		r.EndTime = endTime
	} else {
		today := carbon.Parse(carbon.Now().ToDateString()).ToStdTime()
		r.Tx = r.Tx.Where(m.CreatedDate.Eq(today))
		r.StartTime = carbon.Parse(carbon.Now().ToDateString()).Timestamp()
		r.EndTime = r.StartTime + 86399
	}
	return r
}

// 分页
func (r GoodsDailyReport) WithPaginate(page, limit int) GoodsDailyReportInterface {
	r.Page = page
	r.Limit = limit
	return r
}

// 分组类型
func (r GoodsDailyReport) WithGroupType(Type int) GoodsDailyReportInterface {
	r.GroupType = Type
	return r
}

func (r GoodsDailyReport) HandleGroup() []field.Expr {
	m := r.Query.GoodsDailyReport

	selectField := []field.Expr{
		m.MerchantID,
		m.CreatedDate,
	}
	if r.GroupType == 0 { // 默认分组
		selectField = append(selectField, m.RobotName, m.ProvinceID, m.CityID, m.LocationID)
		r.Tx.Group(m.CreatedDate, m.GoodsID, m.RobotName).
			Order(m.CreatedDate.Desc(), m.GoodsID, m.RobotName)
	} else if r.GroupType == 1 { // 机器分组
		selectField = append(selectField, m.RobotName, m.ProvinceID, m.CityID, m.LocationID)
		r.Tx.Group(m.RobotName).
			Order(m.RobotName)
	} else if r.GroupType == 2 { // 商户分组
		r.Tx.Group(m.MerchantID).
			Order(m.MerchantID)
	} else if r.GroupType == 3 { // 商场分组
		selectField = append(selectField, m.ProvinceID, m.CityID, m.LocationID)
		r.Tx.Group(m.LocationID).
			Order(m.LocationID)
	} else if r.GroupType == 4 { // 日期分组
		r.Tx.Group(m.CreatedDate).
			Order(m.CreatedDate.Desc())
	} else if r.GroupType == 5 { // 城市分组
		selectField = append(selectField, m.ProvinceID, m.CityID)
		r.Tx.Group(m.CityID).
			Order(m.CityID)
	} else if r.GroupType == 6 { // 商品分组
		r.Tx.Group(m.GoodsName).
			Order(m.GoodsName, m.CreatedDate.Desc())
	}
	return selectField
}

// 排序类型
// 1_1 -- 实付金额降序
// 1_2 -- 实付金额升序
// 2_1 -- 退款金额降序
// 2_2 -- 退款金额升序
// 3_1 -- 时间降序
// 3_2 -- 时间升序
// 4_1 -- 实付数量降序
// 4_2 -- 实付数量升序
func (r GoodsDailyReport) WithOrderType(orderType string) GoodsDailyReportInterface {
	m := r.Query.GoodsDailyReport
	if orderType == "1_1" {
		r.Tx = r.Tx.Order(m.PaymentAmount.Sum().Desc())
	} else if orderType == "1_2" {
		r.Tx = r.Tx.Order(m.PaymentAmount.Sum())
	} else if orderType == "2_1" {
		r.Tx = r.Tx.Order(m.RefundAmount.Sum().Desc())
	} else if orderType == "2_2" {
		r.Tx = r.Tx.Order(m.RefundAmount.Sum())
	} else if orderType == "3_1" {
		r.Tx = r.Tx.Order(m.CreatedDate.Desc())
	} else if orderType == "3_2" {
		r.Tx = r.Tx.Order(m.CreatedDate)
	} else if orderType == "4_1" {
		r.Tx = r.Tx.Where(m.TransactionAmount.Gt(0)).
			Order(m.TotalPaidOrder.Sum().Desc())
	} else if orderType == "4_2" {
		r.Tx = r.Tx.Where(m.TransactionAmount.Gt(0)).
			Order(m.TotalPaidOrder.Sum())
	}
	return r
}

// 汇总类型
func (r GoodsDailyReport) WithSummary(summary int) GoodsDailyReportInterface {
	r.Summary = summary
	return r
}

// 计算汇总数据,动态返回字段
func (r GoodsDailyReport) ReportSummary() (summary *models.GoodsDailyReport) {
	selectField := r.getSelectField()
	tx := r.Tx.WithContext(r.Ctx)
	summary, _ = tx.Limit(-1).
		Offset(-1).
		Select(selectField...).
		Take()
	return summary
}

// 获取列表
func (r GoodsDailyReport) List() (result []*models.GoodsDailyReport, total int64, summary *models.GoodsDailyReport, err error) {
	if r.Summary != 0 { // 为0时不汇总
		summary = r.ReportSummary()
	}
	// 拼接Group,确定查询字段
	normalField := r.HandleGroup()
	// 获取指定数据类型
	selectField := r.getSelectField()
	// 拼接常规字段
	selectField = append(selectField, normalField...)

	result, total, err = r.Tx.WithContext(r.Ctx).
		Select(selectField...).
		FindByPage(Offset(r.Page, r.Limit))
	return
}

// 新增编辑
func (GoodsDailyReport) Save(
	ctx context.Context, db *gorm.DB,
	MerchantID, GoodsID, GoodsName, RobotName, Date, ProvinceID, CityID, LocationID string,
	options ...GoodsDailyReportOption,
) (err error) {
	m := dal.Use(db).GoodsDailyReport

	var update GoodsDailyReportSave
	update.MerchantID = &MerchantID
	update.ProvinceID = &ProvinceID
	update.CityID = &CityID
	update.LocationID = &LocationID
	update.UpdateFields = append(update.UpdateFields, m.MerchantID, m.ProvinceID, m.CityID, m.LocationID)

	for _, option := range options {
		option(&update)
	}

	dailyRobotNameCount, _ := m.WithContext(ctx).Where(
		m.GoodsID.Eq(GoodsID),
		m.RobotName.Eq(RobotName),
		m.CreatedDate.Eq(carbon.ParseByLayout(Date, carbon.DateLayout).ToStdTime()),
	).Count()
	if dailyRobotNameCount > 0 { // 编辑
		m.WithContext(ctx).Where(
			m.GoodsID.Eq(GoodsID),
			m.RobotName.Eq(RobotName),
			m.CreatedDate.Eq(carbon.ParseByLayout(Date, carbon.DateLayout).ToStdTime()),
		).Select(update.UpdateFields...).
			Updates(&update)
	} else { // 新增
		update.ID, _ = helper.UUID{}.String()
		createdDate := carbon.ParseByLayout(Date, carbon.DateLayout).ToStdTime()
		update.CreatedDate = &createdDate
		update.RobotName = &RobotName
		update.GoodsID = &GoodsID
		update.GoodsName = &GoodsName
		m.WithContext(ctx).Create(&update.GoodsDailyReport)
	}

	return
}

type GoodsDailyReportSave struct {
	models.GoodsDailyReport
	UpdateFields []field.Expr `gorm:"-"`
}
type GoodsDailyReportOption func(*GoodsDailyReportSave)

// GMV
func (r GoodsDailyReport) WithGMV(value float64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.GMV)
		s.GMV = &value
	}
}

// 实付金额
func (r GoodsDailyReport) WithPaymentAmount(value float64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.PaymentAmount)
		s.PaymentAmount = &value
	}
}

// 交易金额
func (r GoodsDailyReport) WithTransactionAmount(value float64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.TransactionAmount)
		s.TransactionAmount = &value
	}
}

// 优惠金额
func (r GoodsDailyReport) WithDiscountAmount(value float64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.DiscountAmount)
		s.DiscountAmount = &value
	}
}

// 退款金额
func (r GoodsDailyReport) WithRefundAmount(value float64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.RefundAmount)
		s.RefundAmount = &value
	}
}

// 抽奖赠送
func (r GoodsDailyReport) WithGiveAmount(value float64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.GiveAmount)
		s.GiveAmount = &value
	}
}

// 创单笔数
func (r GoodsDailyReport) WithTotalOrder(value int64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.TotalOrder)
		s.TotalOrder = &value
	}
}

// 支付笔数
func (r GoodsDailyReport) WithTotalPaidOrder(value int64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.TotalPaidOrder)
		s.TotalPaidOrder = &value
	}
}

// 未支付笔数
func (r GoodsDailyReport) WithTotalNotPaidOrder(value int64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.TotalNotPaidOrder)
		s.TotalNotPaidOrder = &value
	}
}

// 退款笔数
func (r GoodsDailyReport) WithTotalRefundOrder(value int64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.TotalRefundOrder)
		s.TotalRefundOrder = &value
	}
}

// 支付人数
func (r GoodsDailyReport) WithTotalPaidUser(value int64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.TotalPaidUser)
		s.TotalPaidUser = &value
	}
}

// 商品点击量
func (r GoodsDailyReport) WithTotalGoodsClick(value int64) GoodsDailyReportOption {
	return func(s *GoodsDailyReportSave) {
		s.UpdateFields = append(s.UpdateFields, r.Query.GoodsDailyReport.TotalGoodsClick)
		s.TotalGoodsClick = &value
	}
}
